﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace machines_lib
{
    public class TMTape
    {
        private char blank;
        private Deque<char> deck;

        // NOTE: After construction of the TMTape,
        //  the iterator should never refer to the 'begin' or 'end'
        //  nodes of the underlying deque.
        private Deque<char>.DequeEnumerator iterator;

        internal TMTape(char blankSymbol)
        {
            blank = blankSymbol;
            deck = new Deque<char>();
            iterator = deck.GetDequeEnumerator();
            deck.Push_Back(blank);      // Print a blank character to the tape
            iterator.MoveNext();        // Advance iterator to the blank character we just printed
        }

        internal TMTape(char blankSymbol, IEnumerable<char> initialConfiguration, int initialPosition)
        {
            if (initialPosition < 0)
                throw new IndexOutOfRangeException("initialPosition must be non-negative");

            blank = blankSymbol;
            deck = new Deque<char>(initialConfiguration);
            iterator = deck.GetDequeEnumerator();

            for (int x = 0; x < initialPosition; ++x)
                if (!iterator.MoveNext())
                    throw new IndexOutOfRangeException("initialPosition must be less than the length of initialConfiguration");
        }

        /// <summary>
        /// Advance the tape one position to the left. If there are no
        /// tape cells to the left of the current position, a new cell will
        /// be created with a blank character.
        /// </summary>
        /// <returns>The newly-read character</returns>
        internal char AdvanceLeft()
        {
            // If there is no character to the left of the iterator,
            // then insert a blank character before advancing left
            if (!iterator.HasPrevious())
                iterator.InsertBefore(blank);

            iterator.MovePrevious();

            return iterator.Current;
        }

        /// <summary>
        /// Advance the tape one position to the right. If there are no
        /// tape cells to the right of the current position, a new cell will
        /// be created with a blank character.
        /// </summary>
        /// <returns>The newly-read character</returns>
        internal char AdvanceRight()
        {
            // If there is no character to the right of the iterator,
            // then insert a blank character before advancing right
            if (!iterator.HasNext())
                iterator.InsertAfter(blank);

            iterator.MoveNext();

            return iterator.Current;
        }

        /// <summary>
        /// Get or set the character in the current position on the tape
        /// </summary>
        internal char Current
        {
            get { return iterator.Current; }
            set { iterator.Current = value; }
        }

        public override string ToString()
        {
            string result = String.Empty;

            foreach (char c in deck)
                result += c;

            return result;
        }

        public Deque<char> GetDeck()
        {
            return deck;
        }
    }
}
